// Code copyright Excitation Ltd 2007
using System;
using System.Collections;
using CloneUserQuery.CrmSdk;
using CloneUserQuery.MetadataSdk;
using System.Xml;
namespace CopyUserQuery
{
	public class CopyQuery
	{
		private const string CRMSERVICESUFFIX = "mscrmservices/2006/crmservice.asmx";
		private const int QUERYTYPE = 16;
		CrmService svcCrm;
		Guid srcOwnerId;
		Hashtable htUsers;

		public CopyQuery() : this (null, null) {}
		public CopyQuery(string Url) : this (Url, null) {}
		public CopyQuery(string Url, string SourceOwner)
		{
			try
			{
				svcCrm = new CrmService();
				SetService(svcCrm, Url, CRMSERVICESUFFIX);
				QueryByAttribute qeUsers = new QueryByAttribute();
				qeUsers.EntityName = EntityName.systemuser.ToString();
				qeUsers.ColumnSet = CreateColumnSet(new string[] {"systemuserid", "fullname"});
				qeUsers.Attributes = new string[] {"isdisabled", "setupuser"};
				qeUsers.Values = new object[] {false, false};
				BusinessEntityCollection becUsers = svcCrm.RetrieveMultiple(qeUsers);
				htUsers = new Hashtable(becUsers.BusinessEntities.Length);	// Store user info in hashtable for future reference
				foreach (systemuser user in becUsers.BusinessEntities)
					htUsers.Add(user.fullname, user.systemuserid.Value);
				if (SourceOwner != null && SourceOwner != "")				// if Owner supplied then use that
					srcOwnerId = (Guid) htUsers[SourceOwner];
				else														// otherwise use current user
				{
					WhoAmIResponse resp = (WhoAmIResponse) svcCrm.Execute(new WhoAmIRequest());
					srcOwnerId = resp.UserId;
				}
			}
			catch (System.Web.Services.Protocols.SoapException ex)
			{
				throw new Exception("Error in CloneQuery constructor: " + ex.Detail.InnerXml);
			}
			catch (Exception ex)
			{
				throw new Exception("Error in CloneQuery constructor: " + ex.Message);
			}
		}
		public Guid[] GetAllUsers()
		{
			Guid[] users = new Guid[htUsers.Values.Count];
			IEnumerator en = htUsers.Values.GetEnumerator();
			int i = 0;
			while (en.MoveNext())
				users[i++] = (Guid) en.Current;
			return users;
		}
		public Guid[] GetUserIds(string[] DestinationUsers)
		{
			Queue qId = new Queue();
			foreach (string user in DestinationUsers)
				if (htUsers.ContainsKey(user))
					qId.Enqueue((Guid) htUsers[user]);
			Guid[] users = new Guid[qId.Count];
			qId.CopyTo(users, 0);
			return users;
		}
		public int DoClone(string ViewName, Guid[] DestinationUsers)
		{
			int count = 0;
			try
			{
				QueryByAttribute qeSrc = MakeQuery(srcOwnerId, ViewName);	// Build a query expression to retrieve the view
				svcCrm.CallerIdValue = GetCallerId(srcOwnerId);		// Set callerId to use source owner
				BusinessEntityCollection srcQueries = svcCrm.RetrieveMultiple(qeSrc);
				foreach (userquery srcQuery in srcQueries.BusinessEntities)
				{
					foreach (Guid destUser in DestinationUsers)
					{
						if (destUser == srcOwnerId)					// Ignore the original user
							continue;
						svcCrm.CallerIdValue = GetCallerId(destUser);	// Now run under the context of the destination user								
						try
						{
							srcQuery.userqueryid = null;			// Remove the exisitng primary key value
							Guid idNew = svcCrm.Create(srcQuery);
							count++;
						}
						catch (System.Web.Services.Protocols.SoapException ex)
						{
							XmlDocument doc = new XmlDocument();
							doc.LoadXml(ex.Detail.InnerXml);
							XmlNodeList code = doc.GetElementsByTagName("code");
							if (code == null || code.Count == 0 || code[0].InnerText != "0x80042f09")	// Ignore error thrown if user has no roles
								throw ex;
						}
					}
				}
			}
			catch (System.Web.Services.Protocols.SoapException ex)
			{
				throw new Exception("Error in DoClone: " + ex.Detail.InnerXml);
			}
			catch (Exception ex)
			{
				throw new Exception("Error in DoClone: " + ex.Message);
			}
			return count;
		}
		private CallerId GetCallerId(Guid id)
		{
			CallerId ret = new CallerId();
			ret.CallerGuid = id;
			return ret;
		}
		private QueryByAttribute MakeQuery(Guid OwnerId, string ViewName)
		{
			QueryByAttribute qe = new QueryByAttribute();
			qe.EntityName = EntityName.userquery.ToString();
			qe.ColumnSet = CreateColumnSet(new string[] {"querytype", "name", "returnedtypecode", "description", "fetchxml", "columnsetxml", "layoutxml"});
			qe.Attributes = new string[] {"ownerid", "name", "querytype"};
			qe.Values = new object[] {OwnerId, ViewName, QUERYTYPE};
			return qe;
		} 
		private ColumnSet CreateColumnSet(string[] Columns)
		{
			ColumnSet ret = new ColumnSet();
			ret.Attributes = Columns;
			return ret;
		}
		private void SetService(System.Web.Services.Protocols.SoapHttpClientProtocol svc, string Url, string Suffix)
		{
			svc.Credentials = System.Net.CredentialCache.DefaultCredentials;
			if (Url != null && Url != "")
			{
				if (!Url.EndsWith(Suffix))
					Url += ((Url.EndsWith("/") == true) ? "" : "/") + Suffix;
				svc.Url = Url;			
			}
		}
	}
}
